/*
 * MIT License
 * 
 * Copyright (c) 2017 wen.gu <454727014@qq.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
* Name: tiny_list.c
*
* Purpose: list data structure and API
*
* Developer:
*   wen.gu , 2016-09-14
*
* TODO:
*
***************************************************************************/

#include <string.h>

#include "tiny_list.h"



/***************************************************************************
*
* macro define
*
***************************************************************************/
#define LOGE printf
#define LOGD printf
#define LOGW printf
/***************************************************************************
*
* data structure define
*
***************************************************************************/

/***************************************************************************
*
* inner API define
*
***************************************************************************/
static inline void tlFreeNode(tiny_list_t* tl, tiny_list_node_t* node)
{
	tl->node_count--;

	if (tl->node_free)
	{
		tl->node_free(node);
	}

	if (tl->head == NULL)
	{
		tl->tail = NULL;
	}
}
/***************************************************************************
*
* API define
*
***************************************************************************/

void tfListInitialize(tiny_list_t* tl, TinyListNodeFreeFunc_t node_free)
{
	memset(tl, 0, sizeof(*(tl)));
	tl->node_free = node_free;
}

tiny_list_node_t* tfListFront(tiny_list_t* tl)
{
	return tl->head;
}

void tfListPopFront(tiny_list_t* tl)
{
	if (tl->head)
	{
		tiny_list_node_t* temp = tl->head;

		tl->head = tl->head->next;
		tlFreeNode(tl, temp);
	}
}

void tfListPushFront(tiny_list_t* tl, tiny_list_node_t* node)
{
	tfListInsertFast(tl, NULL, node);
}

void tfListPushBack(tiny_list_t* tl, tiny_list_node_t* node)
{
	tfListInsertFast(tl, tl->tail, node);
}

void tfListRemoveFast(tiny_list_t* tl,tiny_list_node_t* prev, tiny_list_node_t* node)
{
	if (prev && node)
	{
		if (prev == node)
		{
			if (tl->head == prev)/**mean that remove head node */
			{
				tl->head = node->next;
			}
			else
			{
				LOGW("prev == node, but prev != head, this case is illegal, so here will be remove nothing\n");
				return ;
			}
		}
		else
		{
			prev->next = node->next;
		}
		
		tlFreeNode(tl, node);
	}
}

void tfListInsertFast(tiny_list_t* tl,tiny_list_node_t* prev, tiny_list_node_t* node)
{
	if (node)
	{
		if (prev)
		{
			if (tl->tail == prev)
			{
				tl->tail = node;
			}
			node->next = prev->next;
			prev->next = node;
		}
		else
		{
			if (tl->head == NULL)
			{
				tl->tail = node;
			}

			node->next = tl->head;
			tl->head = node;
		}

		tl->node_count++;
	}
	else
	{
		LOGE(" node is NULL \n");
	}

}

void tfListClear(tiny_list_t* tl)
{
	tiny_list_node_t* head = tl->head;

	while (head)
	{
		tiny_list_node_t* node = head;
		head = head->next;

		if (tl->node_free)
		{
			tl->node_free(node);
		}
	}

	tl->head = NULL;
	tl->tail = NULL;
	tl->node_count = 0;
}

GU32 tfListCount(tiny_list_t* tl)
{
	return tl->node_count;
}

GBOL tfListIsEmpty(tiny_list_t* tl)
{
	return tl->head ? GFALSE : GTRUE;
}

